#include "configuration.h"

/*
    This file is part of Slydini.

    Slydini is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Slydini is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Slydini.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <vector>

#include "../tinyxml/tinyxml.h"

using namespace std;

vector<Configuration*> Configuration::configurations;

Configuration *Configuration::getConfiguration(string filename) {
	for (vector<Configuration*>::iterator I = configurations.begin(); I != configurations.end(); I++) {
		if ((*I)->getFilename() == filename)
			return *I;
	}
	Configuration *created = new Configuration(filename);
	configurations.push_back(created);
	return created;
}

string Configuration::getFilename() {
	return filename;
}

/**
 * \brief Konstruktor klasy, otwiera plik z konfiguracją
 *
 * \param filename nazwa pliku z konfiguracją
 */
Configuration::Configuration(string filename) : filename(filename) {
	doc = new TiXmlDocument(filename.c_str());
	doc->LoadFile();
}

/**
 * \brief Szuka podanej opcji w pliku konfiguracyjnym i zwraca ją jako std::string
 *
 * Opcje wyszukuje się poprzedzając jej nazwę elementami leżącymi wyżej w hierarchi dokumentu, np. 'eigenfaces/faceHeight', szuka opcji
 * faceHeight znajdującej się w elemencie eigenfaces
 *
 * \param query string opisujący szukaną zmienną, w formacie opisanym wyżej
 *
 * \return wartość opcji z pliku lub pusty string
 *
 * \sa queryInt
 */
string Configuration::queryString(string query) {
	vector<string> tokens = tokenize(query);
	vector<string>::iterator I;
	TiXmlNode *current = doc->FirstChild()->NextSibling();
	for (I = tokens.begin(); I != tokens.end(); I++) {
		current = getChild(current,*I);
		if (current == NULL)
			return "";
	}
	return current->FirstChild()->Value();
}

/**
 * \brief Szuka podanej opcji i zwraca ją jako int
 *
 * \param query string opisujący szukaną zmienną, sprawdź opis funkcji queryString, aby poznać format
 * \return wartość opcji jako int
 *
 * \sa queryString
 */
int Configuration::queryInt(string query) {
	string result = queryString(query);
	return atoi(result.c_str()); 
}

/**
 * \brief Szuka podanej opcji i zwraca ją jako double
 *
 * \param query string opisujący szukaną zmienną, sprawdź opis funkcji queryString, aby poznać format
 * \return wartość opcji jako double
 *
 * \sa queryString
 */
double Configuration::queryDouble(string query) {
	float result;
	string s = queryString(query);
	if (sscanf(s.c_str(),"%f",&result)!=1)
		return 0;
	return (double)result;
}

/**
 * \brief Dzieli podany string na tokeny
 *
 * \param str string, który ma być podzielony
 * \param delimiters string, w którym każdy znak jest traktowany jako rozdzielający tokeny
 *
 * \return zbiór ciągów
 */
vector<string> Configuration::tokenize(const string str, const string delimiters) {
	vector<string> tokens;
	string::size_type lastPos = str.find_first_not_of(delimiters, 0);
	string::size_type pos     = str.find_first_of(delimiters, lastPos);

	while (string::npos != pos || string::npos != lastPos) {
		tokens.push_back(str.substr(lastPos, pos - lastPos));
		lastPos = str.find_first_not_of(delimiters, pos);
		pos = str.find_first_of(delimiters, lastPos);
	}
	return tokens;
}

/**
 * \brief Szuka dla danego węzła XML jego potomka o danej nazwie.
 *
 * \param current węzeł, w którym szukać
 * \param name nazwa poszukiwanego węzła potomnego
 *
 * \return wskaźnik na węzeł lub NULL
 */
TiXmlNode *Configuration::getChild(TiXmlNode *current, string name) {
	TiXmlNode *child = current->FirstChild();
	while (child) {
		if (strcmp(child->Value(),name.c_str())==0)
			return child;
		child = child->NextSibling();

	}
	return NULL;

}

void Configuration::storeString(string query, string value) {
	vector<string> tokens = tokenize(query);
	vector<string>::iterator I;
	TiXmlNode *current = doc->FirstChild()->NextSibling();
	for (I = tokens.begin(); I != tokens.end(); I++) {
		current = getChild(current,*I);
		/*if (current == NULL)
			return "";*/
	}
    current->FirstChild()->SetValue(value.c_str());
}

void Configuration::save(){
doc->SaveFile(filename.c_str()) ;   
   
}
